package eitwitter.learning.models;

import eitwitter.learning.CategoryInformations;
import eitwitter.learning.WordInformations;
import eitwitter.normalization.Normalizer;
import eitwitter.storage.Tweet;
import eitwitter.storage.Vocabulary;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Implementation du modele multinomial
 * @author AH & PJ
 */

public class MultinomialModel implements ClassificationModel {
	
	/** Coefficient multiplicateur beta */
	private double coef ;
	
	public MultinomialModel(double coef){
		this.coef = coef;
	}

	/**
	 * Calcule les betas de la categorie suivant le modele multinomial
	 * @param categoryInformations	Categorie dont on veut calculer les betas
	 */
	@Override
	public void computeBetas(CategoryInformations categoryInformations) {

		double totalFreq = categoryInformations.getLearning().getTotalFrequencies();
		
		// Pour tous les mots de la categorie
		for(Map.Entry<Integer, WordInformations> word: categoryInformations.getWords().entrySet()){

			// Nombre d'occurences du mot dans la categorie
			double wordFrequency = word.getValue().getFrequency();

			double betaML = wordFrequency/categoryInformations.getWordsNumber();
			
			double betaGL = categoryInformations.getLearning().getTotalFrequencies(word.getKey()) / totalFreq;
			
			// Calcul du beta du mot
			// Nombre d'occurences du mot / nombre d'occurences de tous les mots
			word.getValue().setBeta(coef*betaML + (1.-coef)*betaGL);
		}

	}

	@Override
	public double computeInference(Tweet tweet,	CategoryInformations categoryInformations) {

		// Decoupage du tweet selon le Normalizer de la categorie
		Normalizer normalizer = categoryInformations.getNormalizer();
		HashMap<String, Integer> tweetWords = normalizer.normalize(tweet.getContent());

		// Reference vers le vocabulaire
		Vocabulary vocabulary = categoryInformations.getVocabulary();

		// On recupere les id des mots du tweet connus dans cette catégorie
		ArrayList<Integer> tweetWordsIds = new ArrayList<Integer>();

		for(String word : tweetWords.keySet()){
			int id = vocabulary.getId(word);

			// Si le mot est connu
			if(id != -1){

				// On l'ajoute
				tweetWordsIds.add(id);
			}
		}

		double inference = 0.0;
		double beta;

		// Parcours de tous les mots de la categorie
		for(Map.Entry<Integer, WordInformations> word : categoryInformations.getWords().entrySet()){
			// On récupère le beta de ce mot
			beta = word.getValue().getBeta();

			// Si le mot courant est contenu dans le tweet
			if(tweetWordsIds.contains(word.getKey())){
				// On recupère sa fréquence dans le tweet
				double frequency = tweetWords.get(vocabulary.get(word.getKey()));

				inference += frequency*Math.log(beta);

				// On le supprime de la liste a analyser
				tweetWordsIds.remove(word.getKey());
			}
		}
		
		return inference;


	}

}
